package stud.mpgame.network.service.ping;

import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import stud.mpgame.network.Message;
import stud.mpgame.network.NetworkMonitor;
import stud.mpgame.network.MessageDescription;
import stud.mpgame.network.util.ResponseUserObject;
import stud.mpgame.network.service.ping.PingNotificationMessageDescription;
import stud.mpgame.network.service.ping.PingRequestMessageDescription;
import stud.mpgame.network.service.ping.PingNotificationUserObject;

/**
 * ...
 * @author Timofeev
 */

class PingService {
    
    private var pingTimer:Timer;
    private var networkMonitor:NetworkMonitor;
    private var notifyClient:Bool;
    
    public function new(networkMonitor:NetworkMonitor, pingTickTime:Int, notifyClient:Bool) {
        MessageDescription.registerDescription(PingNotificationMessageDescription.getInstance());
        MessageDescription.registerDescription(PingRequestMessageDescription.getInstance());
        pingTimer = new Timer(pingTickTime);
        pingTimer.addEventListener(TimerEvent.TIMER, sendPingRequest);
        this.networkMonitor = networkMonitor;
        this.notifyClient = notifyClient;
        networkMonitor.getMessageDispatcher().addResponseMessageReceivedListenerByDescr(PingRequestMessageDescription.getInstance(), pingResponseReceived);        
        networkMonitor.addSessionClosedListener(stop);
    }
    
    public function start():Void {
        pingTimer.start();
    }
    
    public function stop(?e:Event):Void {
        pingTimer.stop();
    }
    
    private function sendPingRequest(e:TimerEvent):Void {
        var message:Message = new Message(networkMonitor, PingRequestMessageDescription.getInstance());
        message.send();
    }
    
    public function pingResponseReceived(message:Message):Void {
        var ping:Int = calculatePing(message);
        networkMonitor.setProperty("ping", ping);
        if (notifyClient) {
            var notificationMessage:Message = new Message(networkMonitor, PingNotificationMessageDescription.getInstance());
            var notificationUserObject:PingNotificationUserObject = new PingNotificationUserObject(ping);
            notificationMessage.putUserObject(notificationUserObject);
            notificationMessage.send();
        }
    }
    
    private function calculatePing(message:Message):Int {
        var responseUserObject:ResponseUserObject = cast(message.getUserObject(ResponseUserObject), ResponseUserObject);
        var pingRequestSentTime:Int = responseUserObject.getSentTime();
        var pingRequestReceivedTime:Int = responseUserObject.getReceivedTime();
        var pingResponseSentTime:Int = message.getSentTime();
        var pingResponseReceivedTime:Int = message.getReceivedTime();
        var serverTimeDifferences = pingResponseReceivedTime - pingRequestSentTime;
        var clientTimeDifferences = pingResponseSentTime - pingRequestReceivedTime;
        return Std.int((serverTimeDifferences - clientTimeDifferences) / 2);
    }
    
}